/*
@file: basic.cpp
@author: ZZH
@date: 2022-05-05
@info: 基本函数库实现文件
*/
#include "libFun.h"
#include "fft.h"

EXPORT void __sin(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);

    for (int i = 0; i < allCalNum; i++) output[i] = sin(arg0[i]);
}

EXPORT void __cos(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);

    for (int i = 0; i < allCalNum; i++) output[i] = cos(arg0[i]);
}

EXPORT void __rand(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;

    srand(time(NULL));

    for (int i = 0; i < allCalNum; i++) output[i] = rand();
}

EXPORT void __inner_max(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);
    BasicType currentMax = 0;

    for (int i = 0; i < allCalNum; i++) currentMax = std::max(arg0[i], currentMax);
    for (int i = 0; i < allCalNum; i++) output[i] = currentMax;
}

EXPORT void __inner_min(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);
    BasicType currentMin = 0;

    for (int i = 0; i < allCalNum; i++) currentMin = std::min(arg0[i], currentMin);
    for (int i = 0; i < allCalNum; i++) output[i] = currentMin;
}

// 使用CPU的rdrand指令产生硬件随机数
EXPORT void hrand(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    for (int i = 0; i < allCalNum; i++) {
#ifndef ANDROID
        asm volatile("rdrand %0" : "=r"(*output));
#else
        output[i] = 0;
#endif
    }
}

EXPORT void __abs(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);

    for (int i = 0; i < allCalNum; i++) output[i] = fabs(arg0[i]);
}

EXPORT void freq(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);

    for (int i = 0; i < allCalNum; i++) output[i] = 2 * M_PI * arg0[i] * pArgs->t[i];
}

EXPORT void __length(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    Complex_t* arg0 = static_cast<Complex_t*>(pArgs->args[0]);

    length(output, arg0, allCalNum);
}

EXPORT void angle(pFunCallArg_t pArgs, BasicType* output)
{
}

EXPORT void conv(pFunCallArg_t pArgs, BasicType* output)
{
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);
    uint32_t len0 = abs(*static_cast<BasicType*>(pArgs->args[1]));
    BasicType* arg1 = static_cast<BasicType*>(pArgs->args[2]);
    uint32_t len1 = abs(*static_cast<BasicType*>(pArgs->args[3]));

    full_conv(output, arg0, len0, arg1, len1);
}

EXPORT void __valid_conv(pFunCallArg_t pArgs, BasicType* output)
{
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);
    uint32_t len0 = abs(*static_cast<BasicType*>(pArgs->args[1]));
    BasicType* arg1 = static_cast<BasicType*>(pArgs->args[2]);
    uint32_t len1 = abs(*static_cast<BasicType*>(pArgs->args[3]));

    valid_conv(output, arg0, len0, arg1, len1);
}

EXPORT void sum(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);
    BasicType res = 0;

    for (int i = 0; i < allCalNum; i++) res += arg0[i];
    for (int i = 0; i < allCalNum; i++) output[i] = res;
}

EXPORT void __sqrt(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);

    for (int i = 0; i < allCalNum; i++) output[i] = sqrtf(arg0[i]);
}

EXPORT void to_signed(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);
    int bits = (int) *static_cast<BasicType*>(pArgs->args[1]);

    uint32_t mask = 1 << (bits - 1);
    uint32_t maxValue = 1 << bits;

    for (int i = 0; i < allCalNum; i++) output[i] = arg0[i] < mask ? arg0[i] : arg0[i] - maxValue;
}

EXPORT void to_unsigned(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);
    int bits = (int) *static_cast<BasicType*>(pArgs->args[1]);

    uint32_t maxValue = 1 << bits;

    for (int i = 0; i < allCalNum; i++) output[i] = arg0[i] > 0 ? arg0[i] : arg0[i] + maxValue;
}

EXPORT void complex(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);
    BasicType* arg1 = static_cast<BasicType*>(pArgs->args[1]);
    pComplex_t out = reinterpret_cast<pComplex_t>(output);

    for (int i = 0; i < allCalNum; i++) {
        out[i].real = arg0[i];
        out[i].image = arg1[i];
    }
}

EXPORT void real(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    Complex_t* arg0 = static_cast<Complex_t*>(pArgs->args[0]);

    for (int i = 0; i < allCalNum; i++) output[i] = arg0[i].real;
}

EXPORT void imag(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    Complex_t* arg0 = static_cast<Complex_t*>(pArgs->args[0]);

    for (int i = 0; i < allCalNum; i++) output[i] = arg0[i].image;
}

EXPORT void integrate(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);

    output[0] = arg0[0];

    for (int i = 1; i < allCalNum; i++) output[i] = output[i - 1] + arg0[i];
}

EXPORT void swap_x(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);

    swap_arr(output, arg0, allCalNum);
}

EXPORT void __normalize(pFunCallArg_t pArgs, BasicType* output)
{
    int allCalNum = pArgs->allCalNum;
    BasicType* arg0 = static_cast<BasicType*>(pArgs->args[0]);

    normalize(output, arg0, allCalNum);
}

// clang-format off

LibFunction_t funcs[] = {
    LIB_FUNCTION(__sin, 1, .name = "sin"),
    LIB_FUNCTION(__cos, 1, .name = "cos"),
    LIB_FUNCTION(__rand, 0, .name = "rand"),
    LIB_FUNCTION(__inner_max, 1, .name = "max"),
    LIB_FUNCTION(__inner_min, 1, .name = "min"),
    LIB_FUNCTION(__abs, 1, .name = "abs"),
    LIB_FUNCTION(hrand, 0),
    LIB_FUNCTION(freq, 1),
    LIB_FUNCTION(__length, 1, .name = "length"),
    // LIB_FUNCTION(angle, 1),
    LIB_FUNCTION(conv, 4),
    LIB_FUNCTION(__valid_conv, 4, .name = "valid_conv"),
    LIB_FUNCTION(sum, 1),
    LIB_FUNCTION(integrate, 1),
    LIB_FUNCTION(__sqrt, 1, .name = "sqrt"),
    LIB_FUNCTION(to_signed, 2),
    LIB_FUNCTION(to_unsigned, 2),
    LIB_FUNCTION(complex, 2),
    LIB_FUNCTION(real, 1),
    LIB_FUNCTION(imag, 1),
    LIB_FUNCTION(swap_x, 1),
    LIB_FUNCTION(__normalize, 1, .name = "normalize"),
    END_OF_LIB
};

register_function_lib(funcs);
